package standalone_storage

import (
	// 项目预置依赖
	"github.com/pingcap-incubator/tinykv/kv/config"
	"github.com/pingcap-incubator/tinykv/kv/storage"
	"github.com/pingcap-incubator/tinykv/proto/pkg/kvrpcpb"
	// 外部依赖
	"github.com/Connor1996/badger"

	// 本项目的依赖
	"github.com/pingcap-incubator/tinykv/kv/util/engine_util"
)

// StandAloneStorage is an implementation of `Storage` for a single-node TinyKV instance. It does not
// communicate with other nodes and all data is stored locally.
type StandAloneStorage struct {
	// Your Data Here (1).
	innerEngine *engine_util.Engines
}

func NewStandAloneStorage(inputConfig *config.Config) *StandAloneStorage {
	// Your Code Here (1).
	standAloneStorage := &StandAloneStorage{}
	// 初始化存储引擎
	badgerOptions := badger.DefaultOptions
	badgerOptions.Dir = inputConfig.DBPath
	badgerOptions.ValueDir = inputConfig.DBPath

	singleDB, fail := badger.Open(badgerOptions)
	if fail != nil {
		// 这里先简单进行空指针的处理，后续补充报错日志
		return nil
	}

	// 初始化Engines
	standAloneStorage.innerEngine = engine_util.NewEngines(singleDB, singleDB, inputConfig.DBPath, inputConfig.DBPath)
	return standAloneStorage
}

func (s *StandAloneStorage) Start() error {
	// Your Code Here (1).
	return nil
}

func (s *StandAloneStorage) Stop() error {
	// Your Code Here (1).
	return nil
}

func (s *StandAloneStorage) Reader(ctx *kvrpcpb.Context) (storage.StorageReader, error) {
	// Your Code Here (1).
	r := &StandAloneReader{}
	r.innerStorage = s
	return r, nil
}

func (s *StandAloneStorage) Write(ctx *kvrpcpb.Context, batch []storage.Modify) error {
	// Your Code Here (1).
	wb := &engine_util.WriteBatch{}
	for i := 0; i < len(batch); i++ {
		wb.SetCF(batch[i].Cf(), batch[i].Key(), batch[i].Value())
	}
	return s.innerEngine.WriteKV(wb)
}

type StandAloneReader struct {
	innerStorage *StandAloneStorage
}

func (r StandAloneReader) GetCF(cf string, key []byte) ([]byte, error) {
	responseBytes, fail := engine_util.GetCF(r.innerStorage.innerEngine.Kv, cf, key)
	if fail != nil {
		// 异常时返回全nil
		return nil, nil
	}
	return responseBytes, nil
}

func (r StandAloneReader) IterCF(cf string) engine_util.DBIterator {
	txn := r.innerStorage.innerEngine.Kv.NewTransaction(false)
	var iterator engine_util.DBIterator = engine_util.NewCFIterator(cf, txn)
	return iterator
}

func (r StandAloneReader) Close() {
	//TODO implement me
	panic("implement me")
}
